/*
 * Copyright © 2017 eqxiu.com 北京中网易企秀科技有限公司  All rights reserved.
 */

package cn.hermit.dubbo.docs;

import cn.hermit.data.json.model.JSONArray;
import cn.hermit.data.json.model.JSONFactory;
import cn.hermit.data.json.model.JSONObject;
import cn.hermit.data.swagger.SwaggerContext;
import cn.hermit.dubbo.docs.scanner.HermitScanner;
import cn.hermit.nio.http.Http;
import cn.hermit.nio.http.HttpException;
import cn.hermit.nio.http.server.HttpHandler;
import cn.hermit.nio.http.server.HttpRequest;
import cn.hermit.nio.http.server.HttpResponse;
import cn.hermit.nio.http.server.HttpRouter;
import cn.hermit.nio.http.server.rest.annotation.Resource;
import com.alibaba.dubbo.config.ReferenceConfig;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author JackGao 高建国
 * @description //TODO 设计说明
 * @date 31/5/2017
 */
public class DubboRouter implements HttpRouter {

    private ConcurrentMap<String, HttpHandler> handlerCaches = new ConcurrentHashMap();

    private final SwaggerContext swaggerContext;

    private volatile boolean isSwaggerInit;

    public DubboRouter() {
        swaggerContext = new SwaggerContext();
        handlerCaches.putIfAbsent("/v2/api-docs", new SwaggerDocHandler());
        swaggerContext.put("httpHandlerCaches", handlerCaches);
    }

    @Override
    public HttpHandler route(HttpRequest request) {
        return handlerCaches.get(request.getRequestURI());
    }


    public void appendReferenceConfig(ReferenceConfig referenceConfig) throws Exception {
        if (referenceConfig == null) {
            return;
        }
        if(!isSwaggerInit) {
            initSwagger(referenceConfig);
            isSwaggerInit = true;
        }
        Object api = referenceConfig.get();
        if (api == null) {
            return;
        }
        Class<?> clz = referenceConfig.getInterfaceClass();
        if (clz == null) {
            return;
        }
        Method[] methods = clz.getDeclaredMethods();
        if (methods == null || methods.length == 0) {
            return;
        }

        String basePath = '/' + referenceConfig.getGroup() + '/' + clz.getSimpleName() + '/' + referenceConfig.getVersion();
        Resource resource = clz.getAnnotation(Resource.class);
        if (resource != null) {
            swaggerContext.put("basePath", basePath);
            swaggerContext.put("apiObj", api);
            swaggerContext.put("interface", clz);
            new HermitScanner().scan(swaggerContext);
        } else {
            JSONArray tagsArr = (JSONArray) swaggerContext.getSwagger().getValue("tags");
            JSONObject tagObj = swaggerContext.getJsonFactory().createObject();
            swaggerContext.getJsonFactory().objectEntry(tagObj, "name", clz.getSimpleName());
            swaggerContext.getJsonFactory().objectEntry(tagObj, "description", clz.getName());
            swaggerContext.getJsonFactory().arrayValue(tagsArr, tagObj);
        }


    }


    public class SwaggerDocHandler implements HttpHandler {

        @Override
        public void handle(HttpRequest request, HttpResponse response) throws HttpException {
            byte[] body = swaggerContext.getSwagger().toFormatString().getBytes();
            response.addHeader(Http.CONTENT_TYPE, Http.MEDIA_TYPE_APPLICATION_JSON);
            response.addHeader(Http.CONTENT_LENGTH, body.length);
            response.setBody(body);
        }
    }


    private void initSwagger(ReferenceConfig referenceConfig) {
        JSONFactory jsonFactory = swaggerContext.getJsonFactory();
        JSONObject swagger = swaggerContext.getSwagger();
        jsonFactory.objectEntry(swagger, "swagger", "2.0");

        JSONObject info = jsonFactory.createObject();
        jsonFactory.objectEntry(swagger, "info", info);
        jsonFactory.objectEntry(info, "version", referenceConfig.getApplication().getVersion());
        jsonFactory.objectEntry(info, "title", referenceConfig.getApplication().getName());
        jsonFactory.objectEntry(info, "description", "By " + referenceConfig.getApplication().getOwner());
        jsonFactory.objectEntry(info, "termsOfService", "http://eqxiu.com/terms/");
        JSONObject contact = jsonFactory.createObject();
        jsonFactory.objectEntry(info, "contact", contact);
        jsonFactory.objectEntry(contact, "email", "admin@eqxiu.com");
        JSONObject license = jsonFactory.createObject();
        jsonFactory.objectEntry(info, "license", license);
        jsonFactory.objectEntry(license, "name", "EQXIU");
        jsonFactory.objectEntry(license, "url", "http://eqxiu.com/licenses/LICENSE-2.0.html");


        jsonFactory.objectEntry(swagger, "host", "");
        jsonFactory.objectEntry(swagger, "basePath", "");

        JSONArray tags = jsonFactory.createArray();
        jsonFactory.objectEntry(swagger, "tags", tags);

        JSONArray schemes = jsonFactory.createArray();
        jsonFactory.objectEntry(swagger, "schemes", schemes);
        jsonFactory.arrayValue(schemes, "http");

        JSONObject paths = jsonFactory.createObject();
        jsonFactory.objectEntry(swagger, "paths", paths);

        JSONObject definitions = jsonFactory.createObject();
        jsonFactory.objectEntry(swagger, "definitions", definitions);
    }
}
